#include "stdafx.h"
#include "_XAxis.h"
#include "_GraphLayout.h"


/*
*  @brief Constructor
*/
_XAxis::_XAxis(_GraphLayout& Layout):
    _Axis(Layout)
{
    m_Color = RGB(0xC0, 0xC0, 0xC0);
    m_BaseSize = 20;
}

/*
*  @brief Descructor
*/
_XAxis::~_XAxis(void)
{
}

/*
*  @brief Draws the axis title
*/
void _XAxis::drawTitle()
{
    _u32 XAxisWidth = m_Layout.m_ControlRect.Width() - 2 * m_Layout.m_BorderSize - m_Layout.m_YAxisWidth;
    glViewport(m_Layout.m_BorderSize + m_Layout.m_YAxisWidth,                // X0
               m_Layout.m_BorderSize,                                              // Y0
               XAxisWidth,                                                         // Width
               20                                                                  // Height
              );
    glLoadIdentity();
    gluOrtho2D(0, XAxisWidth, 0, 1);

    // Draw axis title
    if(isTitleVisible())
    {
        // Draw text
        double StringLength = m_Title.GetLength() * 4.0;
        drawText(m_Title, OGL_DRAWABLE_FONT_LUCIDA_CONSOLE_10, XAxisWidth / 2 - StringLength / 2, 0.2, 0, 0, 0);
    }
}

/*
*  @brief Draws the axis background
*/
void _XAxis::drawBackground()
{
    glColor3i(GET_GLINT_R(m_Color), GET_GLINT_G(m_Color), GET_GLINT_B(m_Color));
    glViewport(m_Layout.m_BorderSize,                               // X0
               m_Layout.m_BorderSize,                                      // Y0
               m_Layout.m_ControlRect.Width() - 2 * m_Layout.m_BorderSize, // Width
               m_BaseSize + AxisTitleSize                                  // Height
              );
    // Fill complete viewport with color
    glLoadIdentity();
    gluOrtho2D(0, 1, 0, 1);
    glRectd(0, 0, 1, 1);
}

/*
*  @brief Draws the ticks
*  @param EnableGrid - Enables or disables the grid
*/
void _XAxis::drawTicks(bool EnableGrid)
{
    // Set color
    glColor3i(0, 0, 0);
    // Number of ticks
    _u32 Ticks = (_u32)(m_Range / m_TickSpacing);

    // Workaround empty axis
    if(Ticks < 3)
    {
        m_TickSpacing /= 2;
        Ticks *= 2;
    }

    // Set drawing area
    _u32 AxisHeight = m_BaseSize + AxisTitleSize;
    _u32 AxisWidth =  m_Layout.m_ControlRect.Width() - 2 * m_Layout.m_BorderSize - m_Layout.m_YAxisWidth;
    glViewport(m_Layout.m_BorderSize + m_Layout.m_YAxisWidth,   // X0
               m_Layout.m_BorderSize,                                  // Y0
               AxisWidth,                                              // Width
               m_Layout.m_ControlRect.Height()                         // Height
              );
    glLoadIdentity();
    glOrtho(0, 1, 0, m_Layout.m_ControlRect.Height(), -1, 1);
    double Offset = m_NiceMin;
    double Range  = m_NiceMax - m_NiceMin;
    // Draw the ticks on the right side of the axis
    double CurrentTick = m_FirstTickPosition + m_TickSpacing;
    CStringW TickString = L"";
    CStringW FormatString = L"";
    FormatString.Format(L"%%.%dlf", m_Precision);

    for(_u32 i = 1; i < Ticks; i++)
    {
        // Draw tick string
        double TickPosition = (CurrentTick - Offset) / Range;
        TickString.Format(FormatString, CurrentTick / (pow((double) 10, (int) m_Exponent)));
        double StringLength = TickString.GetLength() * 4.0 / AxisWidth;
        double CenteredTextPosition = TickPosition - StringLength / 2;

        if(TickPosition + StringLength / 2 < (m_NiceMax - Offset) / Range - 40.0 / AxisWidth)
        {
            drawText(TickString, OGL_DRAWABLE_FONT_ARIAL_10, CenteredTextPosition, 15, 0, 0, 0);

            // Draw grid
            if(EnableGrid)
            {
                glEnable(GL_LINE_STIPPLE);
                glLineStipple(1, 0xAAAA);
                glBegin(GL_LINES);
                glVertex2d(TickPosition, AxisHeight);
                glVertex2d(TickPosition, m_Layout.m_ControlRect.Height() - m_Layout.m_TitleHeight - 2 * m_Layout.m_BorderSize);
                glEnd();
                glDisable(GL_LINE_STIPPLE);
            }

            // Draw tick line
            glBegin(GL_LINE_STRIP);
            glVertex2d(TickPosition, AxisHeight);
            glVertex2d(TickPosition, AxisHeight - 7);
            glEnd();
        }

        CurrentTick += m_TickSpacing;
    }
}

/*
*  @brief Check if a specific point is inside the axis
*  @param Point - Point to check
*/
bool _XAxis::isInsideAxis(CPoint& Point)
{
    if((_u32) Point.y > m_Layout.m_ControlRect.bottom - m_Layout.m_XAxisHeight - m_Layout.m_BorderSize &&
       (_u32) Point.x > m_Layout.m_YAxisWidth)
    {
        return true;
    }
    else
    {
        return false;
    }
}

/*
*  @brief Draws the m_Exponent string in the right corner
*/
void _XAxis::drawExponent()
{
    // Setup draw area
    glColor3i(0, 0, 0);
    _u32 AxisMainHeight = m_BaseSize + AxisTitleSize;
    glViewport(m_Layout.m_BorderSize,                            // X0
               m_Layout.m_BorderSize,                                  // Y0
               m_Layout.m_ControlRect.Width() - 2 * m_Layout.m_BorderSize, // Width
               AxisMainHeight                                          // Height
              );
    glLoadIdentity();
    gluOrtho2D(0, m_Layout.m_ControlRect.Width() - 2 * m_Layout.m_BorderSize, 0, 1);
    // Draw the m_Exponent string
    CStringW m_ExponentString = L"";
    m_ExponentString.Format(L"E%d", m_Exponent);
    drawText(m_ExponentString,
             OGL_DRAWABLE_FONT_ARIAL_10,
             m_Layout.m_ControlRect.Width() - 2 * m_Layout.m_BorderSize - 30,
             0.5,
             0, 0, 0
            );
}



/*
*  @brief Draws the axis
*  @param m_Layout.m_BorderSize - Size of the border
*  @param Min        - Minimum value on axis
*  @param Max        - Maximum value on axis
*  @param YAxisWidth - Total y-Axis width
*  @param TitleSize  - Height of the title
*/
void _XAxis::draw(double Min, double Max, bool EnableGrid)
{
    // Check if title is visible
    if(m_Title != L"")
    {
        m_TitleVisible = true;
    }
    else
    {
        m_TitleVisible = false;
    }

    // Draw
    drawBackground();
    drawTitle();
    drawTicks(EnableGrid);
    drawExponent();
}

_u32 _XAxis::getHeight()
{
    return m_BaseSize + AxisTitleSize;
}

void _XAxis::calculateLayout(double Min, double Max, _u32 YAxisWidth)
{
    // Calculates m_NiceMin and m_NiceMax and maximum ticks
    NiceScale(Min, Max);
    setMaxTicks(15);
    // Compute m_Exponent and m_Precision
    m_Exponent = getExponent(m_NiceMin, m_NiceMax);
    m_Precision = getPrecision(m_Exponent);

    // Prevent overlapping of tick strings
    while(m_MaxTicks * (23 + (m_Precision * 8)) > m_Layout.m_ControlRect.Width() - YAxisWidth - 50)
    {
        setMaxTicks(m_MaxTicks - 1);
        NiceScale(Min, Max);
        m_Exponent = getExponent(m_NiceMin, m_NiceMax);
        m_Precision = getPrecision(m_Exponent);
    }

    // Safety checks
    if(m_MaxTicks < 3)
    {
        setMaxTicks(3);
    }

    if(m_Precision > 100)
    {
        m_Precision = 100;
    }

    if(m_Precision < 0)
    {
        m_Precision = 0;
    }

    m_FirstTickPosition = m_NiceMin;

    if(abs(m_FirstTickPosition - m_LastMin) <= m_TickSpacing)
    {
        m_FirstTickPosition = m_LastMin;
        m_LastMin = m_NiceMin;
        m_LastMax = m_NiceMax;
        m_NiceMin = Min;
        m_NiceMax = Max;
    }
    else
    {
        m_LastMin = m_NiceMin;
        m_LastMax = m_NiceMax;
    }
}